import win32gui
import win32api
import win32con
import pyautogui
import win32ui
import cv2
import numpy as np
import time
import sys
import os
import tkinter as tk
from tkinter import ttk
from threading import Thread, Lock, Event
from datetime import datetime, timedelta
import sys
import ntplib
import pytz
import random
import queue


# 资源路径处理
def resource_path(relative_path):
    """ 获取打包后的资源绝对路径 """
    if getattr(sys, 'frozen', False):
        base_path = sys._MEIPASS
    else:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)


# 窗口操作模块
class WindowManager:
    @staticmethod
    def get_window_handle_by_title(window_title):
        return win32gui.FindWindow(None, window_title)

    @staticmethod
    def click_in_window(hwnd, x, y, click_type='left'):
        lParam = win32api.MAKELONG(x, y)
        msg_down = win32con.WM_LBUTTONDOWN if click_type == 'left' else win32con.WM_RBUTTONDOWN
        msg_up = win32con.WM_LBUTTONUP if click_type == 'left' else win32con.WM_RBUTTONUP
        win32gui.PostMessage(hwnd, msg_down, 0, lParam)
        win32gui.PostMessage(hwnd, msg_up, 0, lParam)

    @staticmethod
    def capture_window(hwnd):
        """截取指定窗口句柄的图像并转为OpenCV格式"""
        left, top, right, bottom = win32gui.GetClientRect(hwnd)
        width = right - left
        height = bottom - top

        hwnd_dc = win32gui.GetWindowDC(hwnd)
        mfc_dc = win32ui.CreateDCFromHandle(hwnd_dc)
        save_dc = mfc_dc.CreateCompatibleDC()
        bitmap = win32ui.CreateBitmap()
        bitmap.CreateCompatibleBitmap(mfc_dc, width, height)
        save_dc.SelectObject(bitmap)
        save_dc.BitBlt((0, 0), (width, height), mfc_dc, (0, 0), win32con.SRCCOPY)

        img_data = bitmap.GetBitmapBits(True)
        img = np.frombuffer(img_data, dtype=np.uint8).reshape((height, width, 4))
        img = cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)

        win32gui.DeleteObject(bitmap.GetHandle())
        save_dc.DeleteDC()
        mfc_dc.DeleteDC()
        win32gui.ReleaseDC(hwnd, hwnd_dc)

        return img


# 日志处理模块
class ThreadSafeLogger:
    def __init__(self, log_widget):
        self.log_queue = queue.Queue()
        self.log_widget = log_widget
        self.lock = Lock()

    def log(self, message):
        with self.lock:
            self.log_queue.put(message)

    def flush_logs(self):
        while not self.log_queue.empty():
            try:
                msg = self.log_queue.get_nowait()
                self._append_log(msg)
            except queue.Empty:
                break

    def _append_log(self, message):
        self.log_widget.config(state=tk.NORMAL)
        self.log_widget.insert(tk.END, f"[{time.strftime('%H:%M:%S')}] {message}\n")
        self.log_widget.see(tk.END)
        self.log_widget.config(state=tk.DISABLED)


# 核心业务逻辑
class AutoClickerCore:
    def __init__(self, logger, config):
        self.logger = logger
        self.config = config
        self.operation_lock = Lock()
        self.stop_event = Event()
        self.current_hwnd = None
        self.client_offset = (0, 0)

    def initialize_window(self, hwnd):
        with self.operation_lock:
            try:
                # 设置窗口位置和获取客户区偏移
                win32gui.SetWindowPos(hwnd, None, 7, 9, 640, 512,
                                      win32con.SWP_NOZORDER | win32con.SWP_NOACTIVATE)
                self.client_offset = win32gui.ClientToScreen(hwnd, (0, 0))
                self.current_hwnd = hwnd
                self.logger.log(f"窗口初始化成功 {self.client_offset}")
                return True
            except Exception as e:
                self.logger.log(f"窗口初始化失败: {str(e)}")
                return False

    def find_and_click(self, template_path):
        while not self.stop_event.is_set():
            try:
                points = self._find_template(template_path)
                if points:
                    self._perform_click(points)
                # time.sleep(self.config['interval'])
            except Exception as e:
                self.logger.log(f"操作异常: {str(e)}")

    def _find_template(self, template_path):
        template = cv2.imread(resource_path(template_path), cv2.IMREAD_GRAYSCALE)
        window_img = WindowManager.capture_window(self.current_hwnd)
        window_gray = cv2.cvtColor(window_img, cv2.COLOR_BGR2GRAY)
        w, h = template.shape[::-1]  # 获取模板尺寸
        res = cv2.matchTemplate(window_gray, template, cv2.TM_CCOEFF_NORMED)
        loc = np.where(res >= self.config['threshold'])
        # 生成随机坐标点
        random_points = []
        for pt in zip(*loc[::-1]):  # 遍历每个匹配位置
            x1, y1 = pt[0], pt[1]
            x2 = x1 + w
            y2 = y1 + h

            # 在匹配区域内生成随机坐标
            rand_x = random.randint(x1, x2)
            rand_y = random.randint(y1, y2)
            random_points.append(rand_x)
            random_points.append(rand_y)
        return random_points

    def _perform_click(self, points):
        if points:
            if self.stop_event.is_set():
                return
            x = points[0] - self.client_offset[0]
            y = points[1] - self.client_offset[1]
            self.logger.log(f"操作: 点击坐标 {x},{y},"
                            f" Self.client_offset {self.client_offset[0]},{self.client_offset[1]},")
            WindowManager.click_in_window(self.current_hwnd, x, y)
            time.sleep(0.2)


# GUI主程序
class AutoClickerApp:
    def __init__(self, master):
        self.master = master
        self.running = False
        self._setup_ui()
        self._init_components()
        self._bind_events()

    def _setup_ui(self):
        self.master.title("时空挤号助手 v2.0")
        self.master.geometry("450x400")

        # 控制面板
        control_frame = ttk.LabelFrame(self.master, text="控制")
        control_frame.pack(padx=10, pady=5, fill=tk.X)

        self.btn_start = ttk.Button(control_frame, text="启动")
        self.btn_start.pack(side=tk.LEFT, padx=5)
        ttk.Button(control_frame, text="退出", command=self.master.quit).pack(side=tk.RIGHT, padx=5)

        # 参数配置
        config_frame = ttk.LabelFrame(self.master, text="参数配置")
        config_frame.pack(padx=10, pady=5, fill=tk.X)

        self.sleep_time = tk.DoubleVar(value=0.3)
        self.vip_code = tk.StringVar()

        ttk.Label(config_frame, text="操作间隔（秒）:").pack(side=tk.LEFT)
        self.entry_sleep = ttk.Entry(config_frame, textvariable=self.sleep_time, width=8)
        self.entry_sleep.pack(side=tk.LEFT, padx=5)
        ttk.Button(config_frame, text="恢复默认", command=lambda: self.sleep_time.set(0.3)).pack(side=tk.LEFT)

        ttk.Label(config_frame, text="密钥:").pack(side=tk.LEFT)
        self.entry_vip_code = ttk.Entry(config_frame, textvariable=self.vip_code, width=18)
        self.entry_vip_code.pack(side=tk.LEFT, padx=10)

        # 日志面板
        log_frame = ttk.LabelFrame(self.master, text="运行日志")
        log_frame.pack(padx=10, pady=5, fill=tk.BOTH, expand=True)

        self.log_text = tk.Text(log_frame, height=10, state=tk.DISABLED)
        scrollbar = ttk.Scrollbar(log_frame, command=self.log_text.yview)
        self.log_text.configure(yscrollcommand=scrollbar.set)
        self.log_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

    def _init_components(self):
        self.logger = ThreadSafeLogger(self.log_text)
        self.core = AutoClickerCore(self.logger, {
            'threshold': 0.8,
            'interval': self.sleep_time.get()
        })
        self.window_thread = None
        self.worker_thread = None

    def _bind_events(self):
        self.btn_start.config(command=self.toggle_operation)
        self.master.protocol("WM_DELETE_WINDOW", self.on_close)
        self.master.after(100, self.update_ui)

    def toggle_operation(self):
        if not self.running:
            self.start_operation()
        else:
            self.stop_operation()

    def start_operation(self):
        if not self._validate_vip_code():
            return

        self.running = True
        self.btn_start.config(text="停止")
        self.logger.log("初始化中...")

        # 启动窗口监听线程
        self.window_thread = Thread(target=self._window_listener)
        self.window_thread.daemon = True
        self.window_thread.start()

    def stop_operation(self):
        self.running = False
        self.core.stop_event.set()
        self.btn_start.config(text="启动")
        self.logger.log("操作已停止")

    def _window_listener(self):
        self.logger.log("请点击目标窗口...")
        hwnd = None
        while self.running and not hwnd:
            if win32api.GetAsyncKeyState(win32con.VK_LBUTTON) < 0:
                hwnd = self._get_clicked_window()
                while win32api.GetAsyncKeyState(win32con.VK_LBUTTON) < 0:
                    time.sleep(0.01)
            time.sleep(0.05)

        if hwnd and self.core.initialize_window(hwnd):
            self.worker_thread = Thread(target=self.core.find_and_click, args=("shiyong.png",))
            self.worker_thread.daemon = True
            self.worker_thread.start()

    def _get_clicked_window(self):
        x, y = win32api.GetCursorPos()
        hwnd = win32gui.WindowFromPoint((x, y))
        parent = win32gui.GetParent(hwnd)
        while parent != 0:
            hwnd = parent
            parent = win32gui.GetParent(hwnd)
        return hwnd

    def update_ui(self):
        self.logger.flush_logs()
        self.master.after(100, self.update_ui)

    def _validate_vip_code(self):
        if not self.vip_code.get():
            self.logger.log("请输入有效密钥")
            return False

        if not self._check_validity_period():
            self.logger.log("密钥已过期")
            return False
        return True

    def _check_validity_period(self):
        utc_time = self._get_network_time()
        if not utc_time:
            self.logger.log("无法获取网络时间")
            return False

        beijing_time = utc_time.astimezone(pytz.timezone('Asia/Shanghai'))
        start_date = datetime(2025, 3, 28, tzinfo=beijing_time.tzinfo)

        code_type = self.vip_code.get()
        if code_type == "mh001":
            end_date = start_date + timedelta(days=31)
        elif code_type == "tp001":
            end_date = start_date + timedelta(days=7)
        else:
            self.logger.log("无效密钥")
            return False

        if not (start_date <= beijing_time < end_date):
            self.logger.log(f"服务有效期至 {end_date.strftime('%Y-%m-%d')}")
            return False
        return True

    def _get_network_time(self):
        servers = ['pool.ntp.org', 'cn.pool.ntp.org', 'time.apple.com']
        for server in servers:
            try:
                response = ntplib.NTPClient().request(server, timeout=2)
                return datetime.fromtimestamp(response.tx_time, pytz.utc)
            except Exception:
                continue
        return None

    def on_close(self):
        self.stop_operation()
        self.master.destroy()


if __name__ == "__main__":
    root = tk.Tk()
    app = AutoClickerApp(root)
    root.mainloop()
